Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Roles dynamically added with ngAria #10318

Closed
wants to merge 2 commits into from

Conversation

marcysutton
Copy link
Contributor

To communicate the purpose of custom inputs with a type of range, checkbox or radio, ngAria now dynamically adds roles to custom radio buttons, checkboxes and sliders.

It also adds a role of button to any element with ngClick that is not a button, anchor, input or textarea (such as a div). This feature comes on the heels of #10288, which binds the keypress event for ngClick. With these two changes together, users of assistive technologies will know what they are focused on and be able to operate controls with the keyboard (this is important because ngAria dynamically adds tabIndex="0" with ngClick). However, not all uses of ngClick are used for buttons–sometimes developers bind ng-click on the document. In this scenario, a role can be overridden by the developer if button does not match expected behavior.

Note: This change does not implement any kind of flag allowing the user to opt out of roles being set.

Closes #9254 and #10012.

@googlebot
Copy link

CLAs look good, thanks!

@gkalpak
Copy link
Member

gkalpak commented Dec 4, 2014

I know it is unrelated to this PR, but I was wondering (with regard to line 209):

((type || role) === 'checkbox' ...

What if the element has both a type and a role (and they are different) ?
Is it even a "legitimate" use-case ?

@marcysutton
Copy link
Contributor Author

@gkalpak not for checkbox. <input type="range"> and role="slider" is a use case, and there may be others....but they'd have to be looked at on a case by case basis. I'll keep it in mind though.

@gkalpak
Copy link
Member

gkalpak commented Dec 5, 2014

@marcysutton: Aha, thx. So, if I interpret your answer correctly, in the "general" case each attribute (type, role) should be checked separately:

((type === 'xyz') || (role === 'xyz') || ...)

But for checkboxes and radios, type and role (if set) will be the same, so it is OK to write:

((type || role) === 'xyz')

(which will essentially ignore role if type is defined, but this is OK because role shouldn't be checkbox/radio unless type is checkbox/radio as well.)

Is my thinking correct ?

compileInput('<div ng-click="someFunction()"></div>');
expect(element.attr('role')).toBe('button');
});
it('should not add role="button" to anchor', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: 2 empty lines between each suite/spec/block

@@ -319,6 +329,10 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
}
});
}

if (!elem.attr('role') && (elem[0].nodeName !== 'BUTTON') && (elem[0].nodeName !== 'A')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be more readable to have something like && !IsNodeOneOf(elem, "BUTTON", "A") or something. I don't think it's problematic like this, but if there was one extra condition added it would be really hard to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point. That conditional is a little awkward in its current form.

@marcysutton
Copy link
Contributor Author

@gkalpak there is no "generic" case. ngAria is checking for specific scenarios to add the right attributes. type || role applies correctly to each case where it is being used.

@gkalpak
Copy link
Member

gkalpak commented Dec 5, 2014

OK, thx ! I get it (I think :))

@caitp caitp modified the milestones: 1.3.7, 1.3.8 Dec 9, 2014
@pkozlowski-opensource pkozlowski-opensource modified the milestones: 1.3.8, 1.3.7 Dec 9, 2014
@petebacondarwin petebacondarwin modified the milestones: 1.3.7, 1.3.8 Dec 15, 2014
@btford btford modified the milestones: 1.3.8, 1.3.9 Dec 19, 2014
@lgalfaso lgalfaso removed this from the 1.4.0-beta.2 / 1.3.11 milestone Feb 5, 2015
@marcysutton marcysutton force-pushed the ngaria-roles branch 2 times, most recently from cb6e000 to 0cdd758 Compare February 7, 2015 22:33
@@ -310,6 +320,9 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
return true;
}
}
if (!elem.attr('role') && !isNodeOneOf(elem, ['BUTTON', 'A'])) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blacklist should include INPUT and TEXTAREA

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. But do people put ng-click on those? shudder

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input type=image, type=submit, type=button will all commonly have ng-click attributes applied

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point. I updated the blacklist and added it to the dynamic keypress binding so there would be more consistency.

@marcysutton
Copy link
Contributor Author

@caitp I rebased this branch with the recently merged ngAria changes. The code now uses a node blacklist to add roles and bind keypress events.

@marcysutton
Copy link
Contributor Author

@Narretz @petebacondarwin can you take a look at this PR for adding roles dynamically? It's the last ngAria change that would be great to have in the 1.4 release. Thank you!

});

it('should add missing role="checkbox" to custom input', function() {
scope.$apply('val = true');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this line ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was unnecessary. Cleaned up!

Marcy Sutton added 2 commits February 17, 2015 11:11
@petebacondarwin
Copy link
Contributor

LGTM

@andrewaustin
Copy link
Contributor

Would love to see this in 1.3.x. We have some tags that are clickable and are currently having to do some extra work with ng-keypress to make them fully accessible. Having a blacklist rather than the current div & li whitelist would be extremely useful.

@ginader
Copy link

ginader commented Feb 27, 2015

👍

petebacondarwin pushed a commit that referenced this pull request Mar 2, 2015
petebacondarwin pushed a commit that referenced this pull request Mar 2, 2015
This change adds the missing roles: `slider`, `radio`, `checkbox`

Closes #10012
Closes #10318
petebacondarwin pushed a commit that referenced this pull request Mar 2, 2015
@petebacondarwin
Copy link
Contributor

Landed in master and cherry picked to 1.3.x for good measure.

@marcysutton
Copy link
Contributor Author

Woohoo! Thanks @petebacondarwin! 🎉

hansmaad pushed a commit to hansmaad/angular.js that referenced this pull request Mar 10, 2015
This change adds the missing roles: `slider`, `radio`, `checkbox`

Closes angular#10012
Closes angular#10318
hansmaad pushed a commit to hansmaad/angular.js that referenced this pull request Mar 10, 2015
@marcysutton marcysutton deleted the ngaria-roles branch April 11, 2015 21:14
netman92 pushed a commit to netman92/angular.js that referenced this pull request Aug 8, 2015
This change adds the missing roles: `slider`, `radio`, `checkbox`

Closes angular#10012
Closes angular#10318
netman92 pushed a commit to netman92/angular.js that referenced this pull request Aug 8, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ng-click should do some helpful accessibility things by default